/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package opk.Solver;

import java.awt.Point;
import java.util.ArrayList;
import java.util.HashMap;

import opk.Generator.Edge;
import opk.Generator.Shape;

/**
 *
 * @author Dawid
 */
public class DijkstraAlgorithm
{

    private ArrayList<Shape> allShapes;
    private HashMap<GraphPoint, HashMap<GraphPoint, ArrayList<Edge>>> shortcuts;
    private ArrayList<GraphPoint> graph;

    public HashMap<GraphPoint, HashMap<GraphPoint, ArrayList<Edge>>> getAllShortcuts(ArrayList<Shape> allShapesOuter, boolean coll)
    {
        allShapes = allShapesOuter;
        graph = new ArrayList<GraphPoint>();

        for (Shape shape : allShapes)
        {
            for (Point point : shape.nodes)
            {
                graph.add(new GraphPoint(point));
            }
        }

        for (GraphPoint graphPoint1 : graph)
        {
            for (GraphPoint graphPoint2 : graph)
            {
                if (graphPoint1.equals(graphPoint2))
                {
                    continue;
                }
                Edge edgeToCheck = new Edge(graphPoint1, graphPoint2);

                if(coll)
                {
                    if (!edgeToCheck.intersectsWithAnything2(allShapes))
                    {
                        if (!graphPoint1.equals(graphPoint2))
                        {
                            if (!graphPoint1.getPointsICanSee().contains(graphPoint2))
                            {
                                graphPoint1.addPointICanSee(graphPoint2);
                            }
                            if (!graphPoint2.getPointsICanSee().contains(graphPoint1))
                            {
                                graphPoint2.addPointICanSee(graphPoint1);
                            }
                        }
                    }
                }
                else
                {
                    if (!edgeToCheck.intersectsWithAnything(allShapes))
                    {
                        if (!graphPoint1.equals(graphPoint2))
                        {
                            if (!graphPoint1.getPointsICanSee().contains(graphPoint2))
                            {
                                graphPoint1.addPointICanSee(graphPoint2);
                            }
                            if (!graphPoint2.getPointsICanSee().contains(graphPoint1))
                            {
                                graphPoint2.addPointICanSee(graphPoint1);
                            }
                        }
                    }
                }
            }
        }

        for (GraphPoint graphPoint1 : graph)
        {
            ArrayList<GraphPoint> graphCopy = new ArrayList<GraphPoint>(graph);
            for (GraphPoint graphPoint : graphCopy)
            {
                graphPoint.setCurrentlyShortestRouteLength(Double.MAX_VALUE);
                graphPoint.clearCurrentlyShourtestRoute();
                graphPoint.setWasVisited(false);
            }
            graphPoint1.setCurrentlyShortestRouteLength(0D);
            graphPoint1.setWasVisited(true);

            while (!graphCopy.isEmpty())
            {
                GraphPoint currentGraphPoint = getMinDist(graphCopy);
                graphCopy.remove(currentGraphPoint);

                for (GraphPoint neighbourGraphPoint : currentGraphPoint.getPointsICanSee())
                {
                    if (neighbourGraphPoint.isVisited()) continue;
                    Edge newEdge = new Edge(currentGraphPoint, neighbourGraphPoint);
                    Double newRouteLength = new Double(currentGraphPoint.getCurrentlyShortestRouteLength() + newEdge.getLength());

                    if (Double.compare(newRouteLength, neighbourGraphPoint.getCurrentlyShortestRouteLength())<0)
                    {
                        ArrayList<Edge> newRoute = new ArrayList<Edge>(currentGraphPoint.getCurrentlyShortestRoute());
                        newRoute.add(new Edge(newEdge));

                        neighbourGraphPoint.setCurrentlyShortestRouteLength(newRouteLength);
                        neighbourGraphPoint.setCurrentlyShourtestRoute(newRoute);
                    }
                }

                currentGraphPoint.setWasVisited(true);
            }

            for (GraphPoint graphPoint2 : graph)
            {
                if (!graphPoint1.equals(graphPoint2))
                {
                    ArrayList<Edge> newRoute = (ArrayList<Edge>) graphPoint2.getCurrentlyShortestRoute().clone();
                    Double newDistance = new Double(graphPoint2.getCurrentlyShortestRouteLength());

                    graphPoint1.setDistance(graphPoint2, newDistance);
                    graphPoint1.setRoute(graphPoint2, newRoute);
                }
            }
        }

        shortcuts = new HashMap<GraphPoint, HashMap<GraphPoint, ArrayList<Edge>>>();
        for (GraphPoint graphPoint : graph)
        {
            shortcuts.put(graphPoint, graphPoint.getRoutesToPoints());
        }

        return shortcuts;
    }

    private static GraphPoint getMinDist(ArrayList<GraphPoint> graphCopy)
    {
        GraphPoint graphPointToReturn = graphCopy.get(0);

        for (int i = 1; i < graphCopy.size(); ++i)
        {
            if (graphCopy.get(i).getCurrentlyShortestRouteLength().doubleValue() < graphPointToReturn.getCurrentlyShortestRouteLength().doubleValue())
            {
                graphPointToReturn = graphCopy.get(i);
            }
        }

        return graphPointToReturn;
    }
}
